package com.mercycrazy.recruit.advice;

import com.alibaba.fastjson.JSON;
import com.mercycrazy.recruit.enums.StatusCode;
import com.mercycrazy.recruit.exception.BusinessException;
import com.mercycrazy.recruit.vo.ApiResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 全局异常统一捕获处理
 *
 * @author <a href="mailto:1443424326@qq.com">mercycrazy</a>
 * @since 2023-01-08
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionAdvice {

    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(value = BusinessException.class)
    public ApiResponse<Object> handlerBusinessException(
            HttpServletRequest request, BusinessException ex) {

        StatusCode statusCode = ex.getStatusCode();
        ApiResponse<Object> response = new ApiResponse<>(statusCode);
        log.error("has business error, [{}]", statusCode.getMessage(), ex);
        return response;
    }

    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public ApiResponse<Object> handlerNotValidException(
            HttpServletRequest request, MethodArgumentNotValidException ex) {

        Map<String, String> errors = getErrors(ex.getBindingResult());
        log.info("has valid error: [{}]", JSON.toJSONString(errors), ex);

        ApiResponse<Object> response = new ApiResponse<>(StatusCode.FAILED);
        response.setMessage(printErrors(errors));

        return response;
    }

    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(value = Exception.class)
    public ApiResponse<Object> handlerException(
            HttpServletRequest request, Exception ex) {

        ApiResponse<Object> response = new ApiResponse<>(StatusCode.FAILED);
        log.error("has unknown server error: [{}]", ex.getMessage(), ex);
        return response;
    }

    private String printErrors(Map<String, String> errors) {

        StringBuilder builder = new StringBuilder();
        errors.forEach((key, value) -> builder.append(key)
                .append(": ")
                .append(value)
                .append("; ")
        );

        return builder.substring(0, builder.length() - 2);
    }

    private Map<String, String> getErrors(BindingResult result) {

        Map<String, String> errors = new HashMap<>();

        List<FieldError> fieldErrors = result.getFieldErrors();
        for (FieldError fieldError : fieldErrors) {
            String field = fieldError.getField();
            String message = fieldError.getDefaultMessage();

            errors.put(field, message);
        }

        return errors;
    }
}